package com.bg.test.round;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @Auther: zhengshunzhi
 * @Date: 2018/8/29 10:49
 * @Description: 防止并发操作的轮训请求到各个服务器的测试demo
 */
public class NormalRoundRobin {

    private static List<Server> servers;

    private int currentIndex;
    private int totalServer;

    public NormalRoundRobin() {
        servers = new ArrayList<>();
        servers.add(new Server("192.168.1.2"));
        servers.add(new Server("192.168.1.3"));
        servers.add(new Server("192.168.1.4"));
        servers.add(new Server("192.168.1.5"));
        servers.add(new Server("192.168.1.6"));
        servers.add(new Server("192.168.1.7"));
        servers.add(new Server("192.168.1.8"));
        totalServer = servers.size();
        currentIndex = totalServer - 1;
    }


    // 轮询
    public Server round() {
        currentIndex = (currentIndex + 1) % totalServer;
        return servers.get(currentIndex);
    }


    public static void main(String[] args) {
        final NormalRoundRobin r = new NormalRoundRobin();
        // 不带并发的轮询
        for (int i = 0; i < servers.size(); i++) {
            System.out.println(r.round());
        }

        System.out.println();
        System.out.println("==========================");
        System.out.println();


//        并发工具类（二）同步屏障CyclicBarrier
//        简介
//        CyclicBarrier 的字面意思是可循环使用（Cyclic）的屏障（Barrier）。
//        它要做的事情是，让一组线程到达一个屏障（也可以叫同步点）时被阻塞，直到最后一个线程到达屏障时，屏障才会开门，
//        所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties)，
//        其参数表示屏障拦截的线程数量，每个线程调用await方法告诉CyclicBarrier我已经到达了屏障，然后当前线程被阻塞。
        final CyclicBarrier b = new CyclicBarrier(servers.size());
        // 带并发的轮询
        for (int i = 0; i < servers.size(); i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        b.await();
                        System.out.println(Thread.currentThread().getName() + " " + r.round());
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }, "thread" + i).start();
        }

//        CyclicBarrier和CountDownLatch的区别
//        CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景，比如如果计算发生错误，可以重置计数器，并让线程们重新执行一次。
//        CyclicBarrier还提供其他有用的方法，比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
    }
}
